#include "stdafx.h"
#include "Geometry.h"

#include "Ray.h"

using namespace rt;

static const XMVECTOR EPS_VEC = XMVectorReplicate(0.0001f);
static const float EPS = 0.00001f;

void rt::IntersectSpheres_All_4RaysSingleOrigin(const Sphere * spheres, int num, const Ray4_SingleOrigin & rays, XMVECTOR & intersIndex, XMVECTOR & depth)
{
	for (int i = 0; i < num ; i++)
	{
		// dist = rayOrig - sphereCenter
		XMVECTOR dist = XMVectorSubtract(rays.Orig, spheres[i].CenterAndRadiusSquared); // same for all rays

		// B = dot(dist, rayDir)
		XMVECTOR distX = XMVectorSplatX(dist);
		XMVECTOR mulX = XMVectorMultiply(distX, rays.DirX); // dist.x * rayDir.x
		XMVECTOR distY = XMVectorSplatY(dist);
		XMVECTOR B = XMVectorMultiplyAdd(distY, rays.DirY, mulX);
		XMVECTOR distZ = XMVectorSplatZ(dist);
		B = XMVectorMultiplyAdd(distZ, rays.DirZ, B);

		// C = dot(dist, dist) - radius * radius
		XMVECTOR C =  XMVectorSubtract(XMVector3Dot(dist, dist), XMVectorSplatW(spheres[i].CenterAndRadiusSquared));

		// delta = B*B - C
		XMVECTOR delta = XMVectorSubtract(XMVectorMultiply(B, B), C);

		UINT isDeltaNeg;
		XMVECTOR isDeltaNegMask = XMVectorGreaterOrEqualR(&isDeltaNeg, XMVectorZero(), delta);

		// if delta < 0.0f, move on
		if(XMComparisonAllTrue(isDeltaNeg))
			continue;

		// root = -b - sqrtf(delta)
		XMVECTOR root = XMVectorSubtract(XMVectorNegate(B), XMVectorSqrt(delta));

		// set to meaningful values only components with non-negative delta
		XMVECTOR newDepth = XMVectorSelect(root, XMVectorSplatInfinity(), isDeltaNegMask);
		
		// if newDepth < depth and ...
		UINT isNewDepthLessThanDepth;
		XMVECTOR isNewDepthLessThanDepthMask = XMVectorGreaterR(&isNewDepthLessThanDepth, depth, newDepth);
		if(XMComparisonAllFalse(isNewDepthLessThanDepth))
			continue;
		newDepth = XMVectorSelect(XMVectorZero(), newDepth, isNewDepthLessThanDepthMask); // mask out components that failed comparison,
																								// so they automatically fail next one

		// ... and newDepth > EPSILON ...
		UINT isNewDepthGreaterThanEps;
		XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);

		// ... set new depth(s) and intersected object indices ...
		depth = XMVectorSelect(depth, newDepth, isNewDepthGreaterThanEpsMask);
		intersIndex = XMVectorSelect(intersIndex, XMVectorSetInt(i, i, i, i), isNewDepthGreaterThanEpsMask);

		//// ... and new pointer(s) to intersected object
		//if(isNewDepthGreaterThanEpsMask.m128_f32[0] != 0.0f) intersPtr[0] = (void*)&spheres[i];
		//if(isNewDepthGreaterThanEpsMask.m128_f32[1] != 0.0f) intersPtr[1] = (void*)&spheres[i];
		//if(isNewDepthGreaterThanEpsMask.m128_f32[2] != 0.0f) intersPtr[2] = (void*)&spheres[i];
		//if(isNewDepthGreaterThanEpsMask.m128_f32[3] != 0.0f) intersPtr[3] = (void*)&spheres[i];
	}
}

void rt::IntersectSpheres_All_4Rays(const Sphere * spheres, int num, const Ray4 & rays, XMVECTOR & intersIndex, XMVECTOR & depth, XMVECTOR & intersType)
{
	for (int i = 0; i < num ; i++)
	{
		// B = dot(dist, rayDir)
		XMVECTOR distX = XMVectorSubtract(rays.OrigX, XMVectorSplatX(spheres[i].CenterAndRadiusSquared));
		XMVECTOR distY = XMVectorSubtract(rays.OrigY, XMVectorSplatY(spheres[i].CenterAndRadiusSquared));
		XMVECTOR distZ = XMVectorSubtract(rays.OrigZ, XMVectorSplatZ(spheres[i].CenterAndRadiusSquared));

		XMVECTOR mulX = XMVectorMultiply(distX, rays.DirX); // dist.x * rayDir.x
		XMVECTOR mulY = XMVectorMultiply(distY, rays.DirY); // dist.y * rayDir.y
		XMVECTOR B = XMVectorAdd(mulX, mulY); // dist.x * rayDir.x + dist.y * rayDir.y
		XMVECTOR mulZ = XMVectorMultiply(distZ, rays.DirZ); // dist.z * rayDir.z
		B = XMVectorAdd(B, mulZ); // dist.x * rayDir.x + dist.y * rayDir.y + dist.z * rayDir.z

		// C = dot(dist, dist) - radius * radius
		distX = XMVectorMultiply(distX, distX);
		distY = XMVectorMultiply(distY, distY);
		XMVECTOR distDotDist = XMVectorAdd(distX, distY);
		distZ = XMVectorMultiply(distZ, distZ);
		distDotDist = XMVectorAdd(distDotDist, distZ);

		XMVECTOR C =  XMVectorSubtract(distDotDist, XMVectorSplatW(spheres[i].CenterAndRadiusSquared));

		// delta = B*B - C
		XMVECTOR delta = XMVectorSubtract(XMVectorMultiply(B, B), C);

		UINT isDeltaNeg;
		XMVECTOR isDeltaNegMask = XMVectorGreaterOrEqualR(&isDeltaNeg, XMVectorZero(), delta);

		// if delta < 0.0f, move on
		if(XMComparisonAllTrue(isDeltaNeg))
			continue;

		// root = -b - sqrtf(delta)
		XMVECTOR root = XMVectorSubtract(XMVectorNegate(B), XMVectorSqrt(delta));
		// set to meaningful values only components with non-negative delta
		XMVECTOR newDepth = XMVectorSelect(root, XMVectorSplatInfinity(), isDeltaNegMask);
		// same thing with secondary intersections (from inside the object to outside)
		root = XMVectorAdd(XMVectorNegate(B), XMVectorSqrt(delta));
		XMVECTOR outInters = XMVectorSelect(root, XMVectorSplatInfinity(), isDeltaNegMask);


		//// if newDepth < depth and ...
		//UINT isNewDepthLessThanDepth;
		//XMVECTOR isNewDepthLessThanDepthMask = XMVectorGreaterOrEqualR(&isNewDepthLessThanDepth, depth, newDepth);
		//if(XMComparisonAllFalse(isNewDepthLessThanDepth))
		//	continue;
		//newDepth = XMVectorSelect(XMVectorZero(), newDepth, isNewDepthLessThanDepthMask); // mask out components that failed comparison,
		//// so they automatically fail next one

		//// ... and newDepth > EPSILON ...
		//UINT isNewDepthGreaterThanEps;
		//XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);

		//// ... set new depth(s) and intersected object indices ...
		//depth = XMVectorSelect(depth, newDepth, isNewDepthGreaterThanEpsMask);
		//intersIndex = XMVectorSelect(intersIndex, XMVectorSetInt(i, i, i, i), isNewDepthGreaterThanEpsMask);
		// 

		// if newDepth > EPSILON ...
		UINT isNewDepthGreaterThanEps;
		XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);

		// take into account intersections from inside the box to the outside
		newDepth = XMVectorSelect(outInters, newDepth, isNewDepthGreaterThanEpsMask);
		XMVECTOR newIntersType = XMVectorSelect(XMVectorFalseInt(), XMVectorTrueInt(), isNewDepthGreaterThanEpsMask); // false value in intersType indicates that found intersection is from inside the box

		isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);
		newDepth = XMVectorSelect(XMVectorSplatInfinity(), newDepth, isNewDepthGreaterThanEpsMask);

		// ..  and newDepth < depth
		UINT isNewDepthLessThanDepth;
		const XMVECTOR isNewDepthLessThanDepthMask = XMVectorGreaterR(&isNewDepthLessThanDepth, depth, newDepth);
		depth = XMVectorSelect(depth, newDepth, isNewDepthLessThanDepthMask);
		intersIndex = XMVectorSelect(intersIndex, XMVectorSetInt(i, i, i, i), isNewDepthLessThanDepthMask);
		intersType = XMVectorSelect(intersType, newIntersType, isNewDepthLessThanDepthMask);



		//// ... and new pointer(s) to intersected object
		//if(isNewDepthGreaterThanEpsMask.m128_f32[0] != 0.0f) intersPtr[0] = (void*)&spheres[i];
		//if(isNewDepthGreaterThanEpsMask.m128_f32[1] != 0.0f) intersPtr[1] = (void*)&spheres[i];
		//if(isNewDepthGreaterThanEpsMask.m128_f32[2] != 0.0f) intersPtr[2] = (void*)&spheres[i];
		//if(isNewDepthGreaterThanEpsMask.m128_f32[3] != 0.0f) intersPtr[3] = (void*)&spheres[i];
		// 
	}
}

XMVECTOR rt::IntersectSpheres_Any_4Rays(const Sphere * spheres, int num, const Ray4 & rays, XMVECTOR & maxDepth)
{
	XMVECTOR shadowFoundMask = XMVectorFalseInt();
	for (int i = 0; i < num ; i++)
	{
		// B = dot(dist, rayDir)
		XMVECTOR distX = XMVectorSubtract(rays.OrigX, XMVectorSplatX(spheres[i].CenterAndRadiusSquared));
		XMVECTOR distY = XMVectorSubtract(rays.OrigY, XMVectorSplatY(spheres[i].CenterAndRadiusSquared));
		XMVECTOR distZ = XMVectorSubtract(rays.OrigZ, XMVectorSplatZ(spheres[i].CenterAndRadiusSquared));

		XMVECTOR mulX = XMVectorMultiply(distX, rays.DirX); // dist.x * rayDir.x
		XMVECTOR mulY = XMVectorMultiply(distY, rays.DirY); // dist.y * rayDir.y
		XMVECTOR B = XMVectorAdd(mulX, mulY); // dist.x * rayDir.x + dist.y * rayDir.y
		XMVECTOR mulZ = XMVectorMultiply(distZ, rays.DirZ); // dist.z * rayDir.z
		B = XMVectorAdd(B, mulZ); // dist.x * rayDir.x + dist.y * rayDir.y + dist.z * rayDir.z

		// C = dot(dist, dist) - radius * radius
		distX = XMVectorMultiply(distX, distX);
		distY = XMVectorMultiply(distY, distY);
		XMVECTOR distDotDist = XMVectorAdd(distX, distY);
		distZ = XMVectorMultiply(distZ, distZ);
		distDotDist = XMVectorAdd(distDotDist, distZ);

		XMVECTOR C =  XMVectorSubtract(distDotDist, XMVectorSplatW(spheres[i].CenterAndRadiusSquared));

		// delta = B*B - C
		XMVECTOR delta = XMVectorSubtract(XMVectorMultiply(B, B), C);

		UINT isDeltaNeg;
		XMVECTOR isDeltaNegMask = XMVectorGreaterOrEqualR(&isDeltaNeg, XMVectorZero(), delta);

		// if delta < 0.0f, move on
		if(XMComparisonAllTrue(isDeltaNeg))
			continue;

		// root = -b - sqrtf(delta)
		XMVECTOR root = XMVectorSubtract(XMVectorNegate(B), XMVectorSqrt(delta));

		// set to meaningful values only components with non-negative delta
		XMVECTOR newDepth = XMVectorSelect(root, XMVectorSplatInfinity(), isDeltaNegMask);

		// if newDepth < depth and ...
		UINT isNewDepthLessThanDepth;
		XMVECTOR isNewDepthLessThanDepthMask = XMVectorGreaterR(&isNewDepthLessThanDepth, maxDepth, newDepth);
		if(XMComparisonAllFalse(isNewDepthLessThanDepth))
			continue;
		newDepth = XMVectorSelect(XMVectorZero(), newDepth, isNewDepthLessThanDepthMask); // mask out components that failed comparison,
		// so they automatically fail next one

		// ... and newDepth > EPSILON ...
		UINT isNewDepthGreaterThanEps;
		XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);

		// ... then sample is in shadow
		shadowFoundMask = XMVectorOrInt(shadowFoundMask, isNewDepthGreaterThanEpsMask);

		uint allShadowed;
		XMVectorEqualR(&allShadowed, shadowFoundMask, XMVectorTrueInt());
		if(XMComparisonAllTrue(allShadowed))
			break;
	}
	return shadowFoundMask;
}


void rt::IntersectSpheres_All_1Ray(const Sphere * spheres, int num, const Ray & ray, XMVECTOR & intersIndex, XMVECTOR & depth)
{
	float _depth = XMVectorGetX(depth);
	for (int i = 0; i < num ; i++)
	{
		XMVECTOR dist = XMVectorSubtract(ray.Orig, spheres[i].CenterAndRadiusSquared);

		float B = XMVectorGetX(XMVector3Dot(dist, ray.Dir));

		float C = XMVectorGetX(XMVector3Dot(dist, dist)) - XMVectorGetW(spheres[i].CenterAndRadiusSquared);
		float delta = B*B - C;

		if(delta < 0.0f)
			continue;

		float newDepth = -B - sqrtf(delta);

		if(newDepth < _depth && newDepth > 0.001f)
		{
			_depth = newDepth;
			intersIndex =  XMVectorSetInt(i, i, i, i);
		}

		//UINT isDeltaNeg;
		//XMVectorGreaterOrEqualR(&isDeltaNeg, XMVectorZero(), delta);

		//// if delta < 0.0f, move on
		//if(XMComparisonAllTrue(isDeltaNeg))
		//	continue;

		//XMVECTOR newDepth = XMVectorSubtract(XMVectorNegate(B), XMVectorSqrt(delta));
		//
		//// if newDepth < depth and ...
		//UINT isNewDepthLessThanDepth;
		//XMVectorGreaterOrEqualR(&isNewDepthLessThanDepth, depth, newDepth);
		//if(XMComparisonAllFalse(isNewDepthLessThanDepth))
		//	continue;

		//// ... and newDepth > EPSILON ...
		//UINT isNewDepthGreaterThanEps;
		//XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPSILON);

		//// ... set new depth(s) and intersected object indices ...
		//depth = XMVectorSelect(depth, newDepth, isNewDepthGreaterThanEpsMask);
		//intersIndex = XMVectorSelect(intersIndex, XMVectorSetInt(i, i, i, i), isNewDepthGreaterThanEpsMask);
	}
	depth = XMVectorReplicate(_depth);
}

bool rt::IntersectSpheres_Any_1Ray(const Sphere * spheres, int num, const Ray & ray, XMVECTOR & maxDepth)
{
	float _depth = XMVectorGetX(maxDepth);
	for (int i = 0; i < num ; i++)
	{
		XMVECTOR dist = XMVectorSubtract(ray.Orig, spheres[i].CenterAndRadiusSquared);

		float B = XMVectorGetX(XMVector3Dot(dist, ray.Dir));

		//XMVECTOR radius = XMVectorSplatW(spheres[i].CenterAndRadiusSquared);
		float C = XMVectorGetX(XMVector3Dot(dist, dist)) - XMVectorGetW(spheres[i].CenterAndRadiusSquared);
		//XMVECTOR C =  XMVectorSubtract(XMVector3Dot(dist, dist), radius);
		float delta = B*B - C;
		//XMVECTOR delta = XMVectorSubtract(XMVectorMultiply(B, B), C);

		if(delta < 0.0f)
			continue;

		float newDepth = -B - sqrtf(delta);

		if(newDepth < _depth && newDepth > 0.001f)
		{
			return true;
		}
	}
	return false;

	//for (int i = 0; i < num ; i++)
	//{
	//	XMVECTOR dist = XMVectorSubtract(ray._origin, spheres[i].CenterAndRadiusSquared);

	//	XMVECTOR B = XMVector3Dot(dist, ray._direction);

	//	//XMVECTOR radius = XMVectorSplatW(spheres[i].CenterAndRadiusSquared); // Should be this one, since it results in less instructions and should be faster...
	//	XMVECTOR radius = XMVectorReplicate(XMVectorGetW(spheres[i].CenterAndRadiusSquared)); // ...but apparently this one faster is.
	//																			// What's more weird, is that it seems to work faster only in this specific case.
	//																			// IntersectSpheres_All_1Ray has almost identical code, however in that case, trick doesn't work.
	//	XMVECTOR C =  XMVectorSubtract(XMVector3Dot(dist, dist), radius);
	//	XMVECTOR delta = XMVectorSubtract(XMVectorMultiply(B, B), C);

	//	UINT isDeltaNeg;
	//	XMVectorGreaterOrEqualR(&isDeltaNeg, XMVectorZero(), delta);

	//	// if delta < 0.0f, move on
	//	if(XMComparisonAllTrue(isDeltaNeg))
	//		continue;

	//	XMVECTOR newDepth = XMVectorSubtract(XMVectorNegate(B), XMVectorSqrt(delta));

	//	// if newDepth < maxDepth and ...
	//	UINT isNewDepthLessThanDepth;
	//	XMVectorGreaterOrEqualR(&isNewDepthLessThanDepth, maxDepth, newDepth);
	//	if(XMComparisonAllFalse(isNewDepthLessThanDepth))
	//		continue;

	//	// ... and newDepth > EPSILON ...
	//	UINT isNewDepthGreaterThanEps;
	//	XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPSILON);
	//	if(XMComparisonAllTrue(isNewDepthGreaterThanEps))
	//		return true;
	//}
	//return false;
}

void rt::IntersectPlanes_All_4RaysSingleOrigin(const Plane * planes, int num, const Ray4_SingleOrigin & rays, XMVECTOR & intersIndex, XMVECTOR & depth)
{
	for (int i = 0; i < num ; i++)
	{
		XMVECTOR origDotNorm = XMVector3Dot(rays.Orig, planes[i].NormalAndD);

		// normDotDir = dot(planeNormal, rayDir)
		XMVECTOR normal = planes[i].NormalAndD;

		XMVECTOR normDotDir = XMVectorMultiply(XMVectorSplatX(normal), rays.DirX);
		normDotDir = XMVectorMultiplyAdd(XMVectorSplatY(normal), rays.DirY, normDotDir);
		normDotDir = XMVectorMultiplyAdd(XMVectorSplatZ(normal), rays.DirZ, normDotDir);

		XMVECTOR newDepth = XMVectorDivide(
			XMVectorSubtract(XMVectorSplatW(planes[i].NormalAndD), origDotNorm),
			normDotDir);

		// if newDepth < depth and ...
		UINT isNewDepthLessThanDepth;
		const XMVECTOR isNewDepthLessThanDepthMask = XMVectorGreaterOrEqualR(&isNewDepthLessThanDepth, depth, newDepth);
		if(XMComparisonAllFalse(isNewDepthLessThanDepth))
			continue;
		newDepth = XMVectorSelect(XMVectorZero(), newDepth, isNewDepthLessThanDepthMask); // mask out components that failed comparison,
		// so they automatically fail next one

		// ... and newDepth > EPSILON ...
		UINT isNewDepthGreaterThanEps;
		const XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);

		// ... set new depth(s) and intersected object indices ...
		depth = XMVectorSelect(depth, newDepth, isNewDepthGreaterThanEpsMask);
		intersIndex = XMVectorSelect(intersIndex, XMVectorSetInt(i, i, i, i), isNewDepthGreaterThanEpsMask);
	}
}

void rt::IntersectPlanes_All_4Rays(const Plane * planes, int num, const Ray4 & rays, XMVECTOR & intersIndex, XMVECTOR & depth, XMVECTOR & intersType)
{
	for (int i = 0; i < num ; i++)
	{
		const XMVECTOR normal = planes[i].NormalAndD;
		const XMVECTOR normX = XMVectorSplatX(normal);
		const XMVECTOR normY = XMVectorSplatY(normal);
		const XMVECTOR normZ = XMVectorSplatZ(normal);

		// origDotNorm = dot(raysOrig, planeNormal)
		XMVECTOR origDotNorm = XMVectorMultiply(rays.OrigX, normX);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigY, normY, origDotNorm);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigZ, normZ, origDotNorm);

		// normDotDir = dot(planeNormal, rayDir)
		XMVECTOR normDotDir = XMVectorMultiply(normX, rays.DirX);
		normDotDir = XMVectorMultiplyAdd(normY, rays.DirY, normDotDir);
		normDotDir = XMVectorMultiplyAdd(normZ, rays.DirZ, normDotDir);

		XMVECTOR newDepth = XMVectorDivide(
			XMVectorSubtract(XMVectorSplatW(planes[i].NormalAndD), origDotNorm),
			normDotDir);

		// if newDepth < depth and ...
		UINT isNewDepthLessThanDepth;
		const XMVECTOR isNewDepthLessThanDepthMask = XMVectorGreaterR(&isNewDepthLessThanDepth, depth, newDepth);
		if(XMComparisonAllFalse(isNewDepthLessThanDepth))
			continue;
		newDepth = XMVectorSelect(XMVectorZero(), newDepth, isNewDepthLessThanDepthMask); // mask out components that failed comparison,
																							// so they automatically fail next one

		// ... and newDepth > EPSILON ...
		UINT isNewDepthGreaterThanEps;
		const XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);

		// ... set new depth(s) and intersected object indices ...
		depth = XMVectorSelect(depth, newDepth, isNewDepthGreaterThanEpsMask);
		intersIndex = XMVectorSelect(intersIndex, XMVectorSetInt(i, i, i, i), isNewDepthGreaterThanEpsMask);
	}
}

XMVECTOR rt::IntersectPlanes_Any_4Rays(const Plane * planes, int num, const Ray4 & rays, XMVECTOR & maxDepth)
{
	XMVECTOR shadowFoundMask = XMVectorFalseInt();
	for (int i = 0; i < num ; i++)
	{
		const XMVECTOR normal = planes[i].NormalAndD;
		const XMVECTOR normX = XMVectorSplatX(normal);
		const XMVECTOR normY = XMVectorSplatY(normal);
		const XMVECTOR normZ = XMVectorSplatZ(normal);

		// origDotNorm = dot(raysOrig, planeNormal)
		XMVECTOR origDotNorm = XMVectorMultiply(rays.OrigX, normX);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigY, normY, origDotNorm);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigZ, normZ, origDotNorm);

		// normDotDir = dot(planeNormal, rayDir)
		XMVECTOR normDotDir = XMVectorMultiply(normX, rays.DirX);
		normDotDir = XMVectorMultiplyAdd(normY, rays.DirY, normDotDir);
		normDotDir = XMVectorMultiplyAdd(normZ, rays.DirZ, normDotDir);

		XMVECTOR newDepth = XMVectorDivide(
			XMVectorSubtract(XMVectorSplatW(planes[i].NormalAndD), origDotNorm),
			normDotDir);

		// if newDepth < depth and ...
		UINT isNewDepthLessThanDepth;
		const XMVECTOR isNewDepthLessThanDepthMask = XMVectorGreaterR(&isNewDepthLessThanDepth, maxDepth, newDepth);
		if(XMComparisonAllFalse(isNewDepthLessThanDepth))
			continue;
		newDepth = XMVectorSelect(XMVectorZero(), newDepth, isNewDepthLessThanDepthMask); // mask out components that failed comparison,
																						// so they automatically fail next one

		// ... and newDepth > EPSILON ...
		UINT isNewDepthGreaterThanEps;
		const XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);

		// ... then sample is in shadow
		shadowFoundMask = XMVectorOrInt(shadowFoundMask, isNewDepthGreaterThanEpsMask);

		uint allShadowed;
		XMVectorEqualR(&allShadowed, shadowFoundMask, XMVectorTrueInt());
		if(XMComparisonAllTrue(allShadowed))
			break;
	}
	return shadowFoundMask;
}

void rt::IntersectPlanes_All_1Ray(const Plane * planes, int num, const Ray & ray, XMVECTOR & intersIndex, XMVECTOR & depth)
{
	float _depth = XMVectorGetX(depth);
	for (int i = 0; i < num ; i++)
	{
		//XMVECTOR newDepth = XMVectorDivide( XMVectorSubtract( XMVectorSplatW(planes[i].NormalAndD), XMVector3Dot(ray._origin, planes[i].NormalAndD) ), XMVector3Dot(planes[i].NormalAndD, ray._direction) );
		const float newDepth = (XMVectorGetW(planes[i].NormalAndD) - XMVectorGetX(XMVector3Dot(ray.Orig, planes[i].NormalAndD))) / XMVectorGetX(XMVector3Dot(planes[i].NormalAndD, ray.Dir));

		if(newDepth < _depth && newDepth > 0.001f)
		{
			_depth = newDepth;
			intersIndex =  XMVectorSetInt(i, i, i, i);
		}

		//// if newDepth < depth and ...
		//UINT isNewDepthLessThanDepth;
		//XMVectorGreaterOrEqualR(&isNewDepthLessThanDepth, depth, newDepth);
		//if(XMComparisonAllFalse(isNewDepthLessThanDepth))
		//	continue;

		//// ... and newDepth > EPSILON ...
		//UINT isNewDepthGreaterThanEps;
		//XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPSILON);

		//// ... set new depth(s) and intersected object indices ...
		//depth = XMVectorSelect(depth, newDepth, isNewDepthGreaterThanEpsMask);
		//intersIndex = XMVectorSelect(intersIndex, XMVectorSetInt(i, i, i, i), isNewDepthGreaterThanEpsMask);
	}
	depth = XMVectorReplicate(_depth);
}

bool rt::IntersectPlanes_Any_1Ray(const Plane * planes, int num, const Ray & ray, XMVECTOR & maxDepth)
{
	float _depth = XMVectorGetX(maxDepth);
	for (int i = 0; i < num ; i++)
	{
		//XMVECTOR newDepth = XMVectorDivide( XMVectorSubtract( XMVectorSplatW(planes[i].NormalAndD), XMVector3Dot(ray._origin, planes[i].NormalAndD) ), XMVector3Dot(planes[i].NormalAndD, ray._direction) );
		const float newDepth = (XMVectorGetW(planes[i].NormalAndD) - XMVectorGetX(XMVector3Dot(ray.Orig, planes[i].NormalAndD))) / XMVectorGetX(XMVector3Dot(planes[i].NormalAndD, ray.Dir));

		if(newDepth < _depth && newDepth > 0.001f)
		{
			return true;
		}
		//// if newDepth < depth and ...
		//UINT isNewDepthLessThanDepth;
		//XMVectorGreaterOrEqualR(&isNewDepthLessThanDepth, maxDepth, newDepth);
		//if(XMComparisonAllFalse(isNewDepthLessThanDepth))
		//	continue;

		//// ... and newDepth > EPSILON ...
		//UINT isNewDepthGreaterThanEps;
		//XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPSILON);
		//if(XMComparisonAllTrue(isNewDepthGreaterThanEps))
		//	return true;
	}
	return false;
}

void rt::IntersectBoxes_All_4RaysSingleOrigin(const Box * boxes, int num, const Ray4_SingleOrigin & rays, XMVECTOR & intersIndex, XMVECTOR & depth)
{
	for (int i = 0; i < num ; i++)
	{
		const Plane * planes = boxes[i].Planes;
		XMVECTOR plDep0, plDep1;
		XMVECTOR tNear = XMVectorReplicate(-99999999999.0f), tFar = XMVectorSplatInfinity();
		float origDotNorm;
		XMVECTOR oneOverNormDotDir;
		XMVECTOR normDotDir;
		XMVECTOR cmp;
		XMVECTOR tFarTmp, tNearTmp;

		origDotNorm = XMVectorGetX(XMVector3Dot(rays.Orig, planes[0].NormalAndD));

		XMVECTOR normX = XMVectorSplatX(planes[0].NormalAndD);
		XMVECTOR normY = XMVectorSplatY(planes[0].NormalAndD);
		XMVECTOR normZ = XMVectorSplatZ(planes[0].NormalAndD);
		normDotDir = XMVectorMultiply(normX, rays.DirX);
		normDotDir = XMVectorMultiplyAdd(normY, rays.DirY, normDotDir);
		normDotDir = XMVectorMultiplyAdd(normZ, rays.DirZ, normDotDir);

		oneOverNormDotDir = XMVectorDivide(XMVectorSplatOne(), normDotDir);

		plDep0 = XMVectorMultiply(XMVectorReplicate(XMVectorGetW(planes[0].NormalAndD) - origDotNorm), oneOverNormDotDir);
		plDep1 = XMVectorMultiply(XMVectorReplicate(XMVectorGetW(planes[1].NormalAndD) + origDotNorm), XMVectorNegate(oneOverNormDotDir));

		cmp = XMVectorGreater(plDep0, plDep1);
		tFar = XMVectorSelect(plDep1, plDep0, cmp);
		tNear = XMVectorSelect(plDep0, plDep1, cmp);


		origDotNorm = XMVectorGetX(XMVector3Dot(rays.Orig, planes[2].NormalAndD));

		normX = XMVectorSplatX(planes[2].NormalAndD);
		normY = XMVectorSplatY(planes[2].NormalAndD);
		normZ = XMVectorSplatZ(planes[2].NormalAndD);
		normDotDir = XMVectorMultiply(normX, rays.DirX);
		normDotDir = XMVectorMultiplyAdd(normY, rays.DirY, normDotDir);
		normDotDir = XMVectorMultiplyAdd(normZ, rays.DirZ, normDotDir);

		oneOverNormDotDir = XMVectorDivide(XMVectorSplatOne(), normDotDir);
		
		plDep0 = XMVectorMultiply(XMVectorReplicate(XMVectorGetW(planes[2].NormalAndD) - origDotNorm), oneOverNormDotDir);
		plDep1 = XMVectorMultiply(XMVectorReplicate(XMVectorGetW(planes[3].NormalAndD) + origDotNorm), XMVectorNegate(oneOverNormDotDir));

		cmp = XMVectorGreater(plDep0, plDep1);
		tFarTmp = XMVectorSelect(plDep1, plDep0, cmp);
		tNearTmp = XMVectorSelect(plDep0, plDep1, cmp);
		tFar = XMVectorMin(tFar, tFarTmp);
		tNear = XMVectorMax(tNear, tNearTmp);


		origDotNorm = XMVectorGetX(XMVector3Dot(rays.Orig, planes[4].NormalAndD));

		normX = XMVectorSplatX(planes[4].NormalAndD);
		normY = XMVectorSplatY(planes[4].NormalAndD);
		normZ = XMVectorSplatZ(planes[4].NormalAndD);
		normDotDir = XMVectorMultiply(normX, rays.DirX);
		normDotDir = XMVectorMultiplyAdd(normY, rays.DirY, normDotDir);
		normDotDir = XMVectorMultiplyAdd(normZ, rays.DirZ, normDotDir);

		oneOverNormDotDir = XMVectorDivide(XMVectorSplatOne(), normDotDir);

		plDep0 = XMVectorMultiply(XMVectorReplicate(XMVectorGetW(planes[4].NormalAndD) - origDotNorm), oneOverNormDotDir);
		plDep1 = XMVectorMultiply(XMVectorReplicate(XMVectorGetW(planes[5].NormalAndD) + origDotNorm), XMVectorNegate(oneOverNormDotDir));

		cmp = XMVectorGreater(plDep0, plDep1);
		tFarTmp = XMVectorSelect(plDep1, plDep0, cmp);
		tNearTmp = XMVectorSelect(plDep0, plDep1, cmp);
		tFar = XMVectorMin(tFar, tFarTmp);
		tNear = XMVectorMax(tNear, tNearTmp);


		uint nearGtFar;
		const XMVECTOR nearGtFarMask = XMVectorGreaterR(&nearGtFar, tNear, tFar);
		if(XMComparisonAllTrue(nearGtFar)) continue;

		XMVECTOR newDepth = XMVectorSelect(tNear, XMVectorZero(), nearGtFarMask);

		// if newDepth < depth and ...
		UINT isNewDepthLessThanDepth;
		const XMVECTOR isNewDepthLessThanDepthMask = XMVectorGreaterR(&isNewDepthLessThanDepth, depth, newDepth);
		if(XMComparisonAllFalse(isNewDepthLessThanDepth))
			continue;
		newDepth = XMVectorSelect(XMVectorZero(), newDepth, isNewDepthLessThanDepthMask); // mask out components that failed comparison,
		// so they automatically fail next one

		// ... and newDepth > EPSILON ...
		UINT isNewDepthGreaterThanEps;
		const XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);

		// ... set new depth(s) and intersected object indices ...
		depth = XMVectorSelect(depth, newDepth, isNewDepthGreaterThanEpsMask);
		intersIndex = XMVectorSelect(intersIndex, XMVectorSetInt(i, i, i, i), isNewDepthGreaterThanEpsMask);
	}
}

void rt::IntersectBoxes_All_4Rays(const Box * boxes, int num, const Ray4 & rays, XMVECTOR & intersIndex, XMVECTOR & depth, XMVECTOR & intersType)
{
	for (int i = 0; i < num ; i++)
	{
		const Plane * planes = boxes[i].Planes;
		XMVECTOR plDep0, plDep1;
		XMVECTOR tNear = XMVectorReplicate(-99999999999.0f), tFar = XMVectorSplatInfinity();
		XMVECTOR origDotNorm;
		XMVECTOR oneOverNormDotDir;
		XMVECTOR normDotDir;
		XMVECTOR cmp;
		XMVECTOR tFarTmp, tNearTmp;

		XMVECTOR normX = XMVectorSplatX(planes[0].NormalAndD);
		XMVECTOR normY = XMVectorSplatY(planes[0].NormalAndD);
		XMVECTOR normZ = XMVectorSplatZ(planes[0].NormalAndD);

		origDotNorm = XMVectorMultiply(rays.OrigX, normX);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigY, normY, origDotNorm);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigZ, normZ, origDotNorm);
		
		normDotDir = XMVectorMultiply(normX, rays.DirX);
		normDotDir = XMVectorMultiplyAdd(normY, rays.DirY, normDotDir);
		normDotDir = XMVectorMultiplyAdd(normZ, rays.DirZ, normDotDir);

		oneOverNormDotDir = XMVectorDivide(XMVectorSplatOne(), normDotDir);

		plDep0 = XMVectorMultiply(XMVectorSubtract(XMVectorSplatW(planes[0].NormalAndD), origDotNorm), oneOverNormDotDir);
		plDep1 = XMVectorMultiply(XMVectorAdd(XMVectorSplatW(planes[1].NormalAndD), origDotNorm), XMVectorNegate(oneOverNormDotDir));

		cmp = XMVectorGreater(plDep0, plDep1);
		tFar = XMVectorSelect(plDep1, plDep0, cmp);
		tNear = XMVectorSelect(plDep0, plDep1, cmp);


		normX = XMVectorSplatX(planes[2].NormalAndD);
		normY = XMVectorSplatY(planes[2].NormalAndD);
		normZ = XMVectorSplatZ(planes[2].NormalAndD);

		origDotNorm = XMVectorMultiply(rays.OrigX, normX);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigY, normY, origDotNorm);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigZ, normZ, origDotNorm);

		normDotDir = XMVectorMultiply(normX, rays.DirX);
		normDotDir = XMVectorMultiplyAdd(normY, rays.DirY, normDotDir);
		normDotDir = XMVectorMultiplyAdd(normZ, rays.DirZ, normDotDir);

		oneOverNormDotDir = XMVectorDivide(XMVectorSplatOne(), normDotDir);

		plDep0 = XMVectorMultiply(XMVectorSubtract(XMVectorSplatW(planes[2].NormalAndD), origDotNorm), oneOverNormDotDir);
		plDep1 = XMVectorMultiply(XMVectorAdd(XMVectorSplatW(planes[3].NormalAndD), origDotNorm), XMVectorNegate(oneOverNormDotDir));

		cmp = XMVectorGreater(plDep0, plDep1);
		tFarTmp = XMVectorSelect(plDep1, plDep0, cmp);
		tNearTmp = XMVectorSelect(plDep0, plDep1, cmp);
		tFar = XMVectorMin(tFar, tFarTmp);
		tNear = XMVectorMax(tNear, tNearTmp);


		normX = XMVectorSplatX(planes[4].NormalAndD);
		normY = XMVectorSplatY(planes[4].NormalAndD);
		normZ = XMVectorSplatZ(planes[4].NormalAndD);

		origDotNorm = XMVectorMultiply(rays.OrigX, normX);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigY, normY, origDotNorm);
		origDotNorm = XMVectorMultiplyAdd(rays.OrigZ, normZ, origDotNorm);

		normDotDir = XMVectorMultiply(normX, rays.DirX);
		normDotDir = XMVectorMultiplyAdd(normY, rays.DirY, normDotDir);
		normDotDir = XMVectorMultiplyAdd(normZ, rays.DirZ, normDotDir);

		oneOverNormDotDir = XMVectorDivide(XMVectorSplatOne(), normDotDir);

		plDep0 = XMVectorMultiply(XMVectorSubtract(XMVectorSplatW(planes[4].NormalAndD), origDotNorm), oneOverNormDotDir);
		plDep1 = XMVectorMultiply(XMVectorAdd(XMVectorSplatW(planes[5].NormalAndD), origDotNorm), XMVectorNegate(oneOverNormDotDir));

		cmp = XMVectorGreater(plDep0, plDep1);
		tFarTmp = XMVectorSelect(plDep1, plDep0, cmp);
		tNearTmp = XMVectorSelect(plDep0, plDep1, cmp);
		tFar = XMVectorMin(tFar, tFarTmp);
		tNear = XMVectorMax(tNear, tNearTmp);


		uint nearGtFar;
		const XMVECTOR nearGtFarMask = XMVectorGreaterR(&nearGtFar, tNear, tFar);
		if(XMComparisonAllTrue(nearGtFar)) continue;

		XMVECTOR newDepth = XMVectorSelect(tNear, XMVectorZero(), nearGtFarMask); // intersections from outside to inside of the box
		XMVECTOR outInters = XMVectorSelect(tFar, XMVectorZero(), nearGtFarMask); // intersections from inside the box to the outside

		// if newDepth > EPSILON ...
		UINT isNewDepthGreaterThanEps;
		XMVECTOR isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);

		// take into account intersections from inside the box to the outside
		newDepth = XMVectorSelect(outInters, newDepth, isNewDepthGreaterThanEpsMask);
		XMVECTOR newIntersType = XMVectorSelect(XMVectorFalseInt(), XMVectorTrueInt(), isNewDepthGreaterThanEpsMask); // false value in intersType indicates that found intersection is from inside the box

		isNewDepthGreaterThanEpsMask = XMVectorGreaterR(&isNewDepthGreaterThanEps, newDepth, EPS_VEC);
		newDepth = XMVectorSelect(XMVectorSplatInfinity(), newDepth, isNewDepthGreaterThanEpsMask);

		// ..  and newDepth < depth
		UINT isNewDepthLessThanDepth;
		const XMVECTOR isNewDepthLessThanDepthMask = XMVectorGreaterR(&isNewDepthLessThanDepth, depth, newDepth);
		depth = XMVectorSelect(depth, newDepth, isNewDepthLessThanDepthMask);
		intersIndex = XMVectorSelect(intersIndex, XMVectorSetInt(i, i, i, i), isNewDepthLessThanDepthMask);
		intersType = XMVectorSelect(intersType, newIntersType, isNewDepthLessThanDepthMask);
	}
}

void rt::IntersectBoxes_All_1Ray(const Box * boxes, int num, const Ray & ray, XMVECTOR & intersIndex, XMVECTOR & depth)
{
	float _depth = XMVectorGetX(depth);
	for (int i = 0; i < num ; i++)
	{
		const Plane * planes = boxes[i].Planes;
		float plDep0, plDep1;
		float tNear = -std::numeric_limits<float>::infinity(), tFar = std::numeric_limits<float>::infinity();
		float origDotNorm, oneOverNormDotDir;

		// Tried moving costly division to sse but didn't notice any speedup.
		// Definitely entire method could make smarter use of sse, but I was to lazy.

		origDotNorm = XMVectorGetX(XMVector3Dot(ray.Orig, planes[0].NormalAndD));
		oneOverNormDotDir = 1.0f / XMVectorGetX(XMVector3Dot(planes[0].NormalAndD, ray.Dir));
		plDep0 = (XMVectorGetW(planes[0].NormalAndD) - origDotNorm) * oneOverNormDotDir;
		plDep1 = (XMVectorGetW(planes[1].NormalAndD) + origDotNorm) * -oneOverNormDotDir;

		if(plDep0 > plDep1) { tFar = plDep0; tNear = plDep1; }
		else			    { tFar = plDep1; tNear = plDep0; }

		origDotNorm = XMVectorGetX(XMVector3Dot(ray.Orig, planes[2].NormalAndD));
		oneOverNormDotDir = 1.0f / XMVectorGetX(XMVector3Dot(planes[2].NormalAndD, ray.Dir));
		plDep0 = (XMVectorGetW(planes[2].NormalAndD) - origDotNorm) * oneOverNormDotDir;
		plDep1 = (XMVectorGetW(planes[3].NormalAndD) + origDotNorm) * -oneOverNormDotDir;

		if(plDep0 > plDep1) { tFar = (std::min)(tFar, plDep0); tNear = (std::max)(tNear, plDep1); }
		else				{ tFar = (std::min)(tFar, plDep1); tNear = (std::max)(tNear, plDep0); }

		origDotNorm = XMVectorGetX(XMVector3Dot(ray.Orig, planes[4].NormalAndD));
		oneOverNormDotDir = 1.0f / XMVectorGetX(XMVector3Dot(planes[4].NormalAndD, ray.Dir));
		plDep0 = (XMVectorGetW(planes[4].NormalAndD) - origDotNorm) * oneOverNormDotDir;
		plDep1 = (XMVectorGetW(planes[5].NormalAndD) + origDotNorm) * -oneOverNormDotDir;

		if(plDep0 > plDep1) { tFar = (std::min)(tFar, plDep0); tNear = (std::max)(tNear, plDep1); }
		else				{ tFar = (std::min)(tFar, plDep1); tNear = (std::max)(tNear, plDep0); }

		if(tFar < tNear) continue;

		if(tNear < _depth && tNear > EPS)
		{
			_depth = tNear;
			intersIndex =  XMVectorSetInt(i, i, i, i);
		}
	}
	depth = XMVectorReplicate(_depth);
}

bool rt::IntersectBoxes_Any_1Ray(const Box * boxes, int num, const Ray & ray, XMVECTOR & maxDepth)
{
	float _depth = XMVectorGetX(maxDepth);
	for (int i = 0; i < num ; i++)
	{
		const Plane * planes = boxes[i].Planes;

		XMVECTOR plDep0, plDep1;

		const XMVECTOR origDotNorm = XMVectorSet(
			XMVectorGetX(XMVector3Dot(ray.Orig, planes[0].NormalAndD)),
			XMVectorGetX(XMVector3Dot(ray.Orig, planes[2].NormalAndD)),
			XMVectorGetX(XMVector3Dot(ray.Orig, planes[4].NormalAndD)),
			0.0f);

		const XMVECTOR normDotDir = XMVectorSet(
			XMVectorGetX(XMVector3Dot(planes[0].NormalAndD, ray.Dir)),
			XMVectorGetX(XMVector3Dot(planes[2].NormalAndD, ray.Dir)),
			XMVectorGetX(XMVector3Dot(planes[4].NormalAndD, ray.Dir)),
			0.0f);

		const XMVECTOR oneOverNormDotDir = XMVectorDivide(XMVectorSplatOne(), normDotDir);

		const XMVECTOR d0 = XMVectorSet(XMVectorGetW(planes[0].NormalAndD), XMVectorGetW(planes[2].NormalAndD), XMVectorGetW(planes[4].NormalAndD), 0.0f);
		const XMVECTOR d1 = XMVectorSet(XMVectorGetW(planes[1].NormalAndD), XMVectorGetW(planes[3].NormalAndD), XMVectorGetW(planes[5].NormalAndD), 0.0f);
		plDep0 = XMVectorMultiply(XMVectorSubtract(d0, origDotNorm), oneOverNormDotDir);
		plDep1 = XMVectorMultiply(XMVectorAdd(d1, origDotNorm), XMVectorNegate(oneOverNormDotDir));

		const XMVECTOR dep0GtDep1Mask = XMVectorGreater(plDep0, plDep1);
		const XMVECTOR tFar = XMVectorSelect(plDep1, plDep0, dep0GtDep1Mask);
		const XMVECTOR tNear = XMVectorSelect(plDep0, plDep1, dep0GtDep1Mask);

		const float smallFar = XMVectorGetX( XMVectorMin(
				XMVectorSplatX(tFar),
				XMVectorMin(XMVectorSplatY(tFar), XMVectorSplatZ(tFar))));

		const float bigNear = XMVectorGetX( XMVectorMax(
			XMVectorSplatX(tNear),
			XMVectorMax(XMVectorSplatY(tNear), XMVectorSplatZ(tNear))));

		if(smallFar < bigNear) continue;

		if(bigNear < _depth && bigNear > EPS)
		{
			return true;
		}


		//float plDep0, plDep1;
		//float tNear = -std::numeric_limits<float>::infinity(), tFar = std::numeric_limits<float>::infinity();
		//float origDotNorm, oneOverNormDotDir;

		//// Tried moving costly division to sse but didn't notice any speedup.
		//// Definitely entire method could make smarter use of sse, but I was to lazy.

		//origDotNorm = XMVectorGetX(XMVector3Dot(ray._origin, planes[0].NormalAndD));
		//oneOverNormDotDir = 1.0f / XMVectorGetX(XMVector3Dot(planes[0].NormalAndD, ray._direction));
		//plDep0 = (XMVectorGetW(planes[0].NormalAndD) - origDotNorm) * oneOverNormDotDir;
		//plDep1 = (XMVectorGetW(planes[1].NormalAndD) + origDotNorm) * -oneOverNormDotDir;

		//if(plDep0 > plDep1) { tFar = plDep0; tNear = plDep1; }
		//else			    { tFar = plDep1; tNear = plDep0; }

		//origDotNorm = XMVectorGetX(XMVector3Dot(ray._origin, planes[2].NormalAndD));
		//oneOverNormDotDir = 1.0f / XMVectorGetX(XMVector3Dot(planes[2].NormalAndD, ray._direction));
		//plDep0 = (XMVectorGetW(planes[2].NormalAndD) - origDotNorm) * oneOverNormDotDir;
		//plDep1 = (XMVectorGetW(planes[3].NormalAndD) + origDotNorm) * -oneOverNormDotDir;

		//if(plDep0 > plDep1) { tFar = (std::min)(tFar, plDep0); tNear = (std::max)(tNear, plDep1); }
		//else				{ tFar = (std::min)(tFar, plDep1); tNear = (std::max)(tNear, plDep0); }

		//origDotNorm = XMVectorGetX(XMVector3Dot(ray._origin, planes[4].NormalAndD));
		//oneOverNormDotDir = 1.0f / XMVectorGetX(XMVector3Dot(planes[4].NormalAndD, ray._direction));
		//plDep0 = (XMVectorGetW(planes[4].NormalAndD) - origDotNorm) * oneOverNormDotDir;
		//plDep1 = (XMVectorGetW(planes[5].NormalAndD) + origDotNorm) * -oneOverNormDotDir;

		//if(plDep0 > plDep1) { tFar = (std::min)(tFar, plDep0); tNear = (std::max)(tNear, plDep1); }
		//else				{ tFar = (std::min)(tFar, plDep1); tNear = (std::max)(tNear, plDep0); }

		//if(tFar < tNear) continue;

		//if(tNear < _depth && tNear > EPS)
		//{
		//	return true;
		//}
	}
	return false;
}

void rt::GetSphereIntersectionData(const Sphere & sphere, XMVECTOR intersPoint, IntersectionData & data)
{
	data.Normal =  XMVector3Normalize(XMVectorSubtract(intersPoint, sphere.CenterAndRadiusSquared));
	data.TexCoords = XMVectorSubtract(intersPoint, sphere.CenterAndRadiusSquared);
}

void rt::GetPlaneIntersectionData(const Plane & plane, XMVECTOR intersPoint, IntersectionData & data)
{
	data.Normal = plane.NormalAndD;
	data.TexCoords = intersPoint;
}

void rt::GetBoxIntersectionData(const Box & box, XMVECTOR intersPoint, IntersectionData & data)
{
	for(int i = 0; i < 6; i++)
	{
		float p = XMVectorGetX(XMVector3Dot(box.Planes[i].NormalAndD, intersPoint)) - XMVectorGetW(box.Planes[i].NormalAndD);
		if(abs(p) < EPS)
		{
			data.Normal = box.Planes[i].NormalAndD;
			break;
		}
	}

	data.TexCoords = XMVectorSubtract(intersPoint, box.Position);
}